#include "Session.h"
#include "NetUtil.h"
#include "Packet.h"
#include "Socket.h"

void Session::Write( Packet* pkt )
{
	int psz = pkt->GetSize() + 4 + 2;
	short id = pkt->GetID();

	Buffer* buf = new Buffer(psz);
	buf->putInt(psz);
	buf->putShort(id);

	pkt->Encode(buf);

	m_sendque.enqueue(buf);
}

void Session::SendHeartbeat()
{
	Buffer* buf = new Buffer(6);
	buf->putInt(6);
	buf->putShort(0);

	m_sendque.enqueue(buf);

	UTL_LOG_NORMAL("sne", "session send heartbeat, session id=[%d]", m_id);
}

void Session::OnRecv( const char* data, int len )
{
	if (GetState() == CLOSED)
	{
		UTL_LOG_HIGH("sne", "receive message when close");
		return;
	}

	int need_write = len;
	int offset = 0;

	while (need_write > 0)
	{
		//header receive
		if (m_recv_packet_fragment_offset < 4)
		{
			int nwn = 4 - m_recv_packet_fragment_offset;
			int wn = (need_write >= nwn ? nwn : need_write);

			memcpy(m_recv_packet_fragment_buf + m_recv_packet_fragment_offset, data+offset, wn);
			m_recv_packet_fragment_offset += wn;
			need_write -= wn;
			offset += wn;
		}

		//header receive haven't finished yet
		if (m_recv_packet_fragment_offset < 4)
		{
			return;
		}

		//content receive
		int pkt_len = ntohl(*(int*)m_recv_packet_fragment_buf);
		if (pkt_len > PACKET_BUFFER_SIZE || pkt_len < 6)
		{
			UTL_LOG_HIGH("sne", "error packet length: %d", pkt_len);

			Close();

			return;
		}

		if (m_recv_packet_fragment_offset + need_write >= pkt_len)
		{
			//one packet receive finished
			int writesize = pkt_len - m_recv_packet_fragment_offset;

			memcpy(m_recv_packet_fragment_buf + m_recv_packet_fragment_offset, data+offset, writesize);
			m_recv_packet_fragment_offset = 0;
			need_write -= writesize;
			offset += writesize;

			Buffer* newbuf = new Buffer(pkt_len-4);
			newbuf->putRaw(m_recv_packet_fragment_buf+4, pkt_len-4);
			m_recvque.enqueue(newbuf);
		}
		else
		{
			memcpy(m_recv_packet_fragment_buf + m_recv_packet_fragment_offset, data+offset, need_write);
			m_recv_packet_fragment_offset += need_write;
			need_write = 0;
			offset += need_write;
		}
	}

}

void Session::SendFromBuf()
{
	if (m_state != CONNECTED)
	{
		return;
	}

	if (m_send_packet_size == 0)
	{
		Buffer* buf;
		if (m_sendque.dequeue(buf))
		{
			m_send_packet_size = buf->getSize();

			buf->getRaw(m_send_packet_fragment_buf, m_send_packet_size);
			m_send_packet_fragment_offset = 0;
		}
	}

	if (m_send_packet_size == 0)
	{
		//send finished
	}
	else
	{
		int sn = send(m_socket, 
			m_send_packet_fragment_buf + m_send_packet_fragment_offset,
			m_send_packet_size, 0);

		m_send_packet_size -= sn;
		m_send_packet_fragment_offset += sn;

	}

}

void Session::Close()
{
	SetState(CLOSED);
}

int Session::GetID()
{
	return m_id;
}

void Session::CheckSend()
{
	timeval timeout;

	timeout.tv_sec	= 0;
	timeout.tv_usec = 0;

	fd_set writefds;
	fd_set exceptfds;

	FD_ZERO(&writefds);
	FD_ZERO(&exceptfds);

	FD_SET(m_socket, &writefds);
	FD_SET(m_socket, &exceptfds);
	
	select(0, 0, &writefds, &exceptfds, &timeout);


	if(FD_ISSET(m_socket, &writefds))
	{
		SendFromBuf();
	}

	if(FD_ISSET(m_socket, &exceptfds))
	{
		//ss->Close();
		UTL_LOG_HIGH("sne", "except error: %d", WSAGetLastError());
	}
	
}

void Session::CheckRecv()
{
	timeval timeout;

	timeout.tv_sec	= 0;
	timeout.tv_usec = 0;

	fd_set readfds;
	fd_set exceptfds;

	FD_ZERO(&readfds);
	FD_ZERO(&exceptfds);


	FD_SET(m_socket, &readfds);
	FD_SET(m_socket, &exceptfds);
	

	select(0, &readfds, 0, &exceptfds, &timeout);


	if(FD_ISSET(m_socket, &readfds))
	{
		int nRecv = recv(m_socket, m_tempBuf, SOCK_READ_SIZE, 0);
		if(nRecv > 0)                        
		{
			OnRecv(m_tempBuf, nRecv);
		}
		else if (nRecv == 0)
		{
			UTL_LOG_HIGH("sne", "recv return 0, session will close");
			Close();
		}
		else if (nRecv == WSAEWOULDBLOCK)
		{
			UTL_LOG_HIGH("sne", "recv WSAEWOULDBLOCK");
		}
		else
		{
			Close();
			UTL_LOG_HIGH("sne", "recv error: %d", WSAGetLastError());
		}
	}

	if(FD_ISSET(m_socket, &exceptfds))
	{
		//ss->Close();
		UTL_LOG_HIGH("sne", "except error: %d", WSAGetLastError());
	}
	
}

bool Session::IsClosed()
{
	return (m_state == CLOSED);
}

Session::Session(int id, int sock, Socket* pSocket, int local_ip, unsigned short local_port, int remote_ip, unsigned short remote_port):
m_id(id),
m_socket(sock),
m_local_ip(local_ip),
m_local_port(local_port),
m_remote_ip(remote_ip),
m_remote_port(remote_port),
m_state(CONNECTED), 
m_recv_packet_fragment_offset(0),
m_send_packet_fragment_offset(0),
m_send_packet_size(0),
m_release(false)
{
	m_pSocket = pSocket;
}

Session::~Session()
{
	if (m_socket != -1)
	{
		closesocket(m_socket);
		UTL_LOG_HIGH("sne", "close socket=[%d]", m_socket);
	}
}

//===================================================================================================
bool SessionTask::DoTask()
{	
	if (!m_session->IsClosed())
	{
		m_session->CheckRecv();
		m_session->CheckSend();
	}

	return m_session->IsRelease();
}

SessionTask::SessionTask( Session* ss )
: m_session(ss)
{

}

SessionTask::~SessionTask()
{
	delete m_session;
}

void SessionTask::Wait()
{
	Sleep(1);
}
